



#include "../inc/dllemvb.h"



#ifdef CONTACT_EMV

#define PINPAD_VALID 1


unsigned char Emvb_veritysetcvrunknown(void)
{

	dllemvb_avl_createsettagvalue((unsigned char *)TAG_CVMResult,(unsigned char *)"\x3F\x00\x00",3);
	return EMV_OK;
	
}
/*******************************************************************
��    ��:
��������: unsigned char PaypassInitCardHolderVerify(AppUnionStruct *tempApp_UnionStruct)
��������: ��ʼ���ֿ�����֤
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ: 20130731
********************************************************************/
unsigned char EmvbInitCardHolderVerify(EMVBAppUnionStruct *tempApp_UnionStruct,CVMSTRCUT *CVMdata)
{
	unsigned char i;
	unsigned char AIP[2];
	unsigned char CVMResult[3];
    unsigned char CVMListbExist;
	EMVTAGCVLITEM *CVMListitem;

	
	
    memset(AIP,0,sizeof(AIP));
    dllemvb_avl_gettagvalue_spec((unsigned char *)TAG_AIP,AIP,0,2);
	
    
    
	if(!(AIP[0]&0x10))   //����֧�ֳֿ�����֤
	{
	    
		return Emvb_veritysetcvrunknown();
	}
	
	//get cvm list in the card, if not available, return
	CVMListitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_CVMList,&CVMListbExist);
	if(CVMListbExist==0x00)//CVM List is absent.
	{
		return Emvb_veritysetcvrunknown();
	}
	
	if(CVMListitem->len<10||(CVMListitem->len%2))
	{
		return Emvb_veritysetcvrunknown();
	}
	
	//to compatibal with PC and 51MCU and MCVZ328 MCU,make the long integer independent of byte order.
	memcpy(&CVMdata->CVM_X[2],CVMListitem->data,4);
	memcpy(&CVMdata->CVM_Y[2],&CVMListitem->data[4],4);
	
	CVMdata->CVRListLen=(CVMListitem->len-8)>>1;
	for(i=0;i<CVMdata->CVRListLen;i++)//����CVM������2�ֽ�
	{
		CVMdata->CVRList[i].method = CVMListitem->data[i*2+8];
		CVMdata->CVRList[i].condition = CVMListitem->data[i*2+9];
	}
	

	CVMResult[0]=0x3f;    //sxl ��ʼ��result
	CVMResult[1]=0;
	CVMResult[2]=CVR_FAIL;
	dllemvb_avl_createsettagvalue((unsigned char *)TAG_CVMResult,CVMResult,3);
	#ifdef EMVB_DEBUG
    emvb_printf("\r\nEmvbInitCardHolderVerify4\r\n");
	#endif
		
	return EMV_PARSESUC;
}



//20130731
unsigned char Emvb_CheckIfSupportCVM(unsigned char method)   //20090202
{
    unsigned char temp;
	unsigned char TermCapab[3];
    unsigned char ret;
	
	temp = method&0x3F;

	memset(TermCapab,0,sizeof(TermCapab));
    dllemvb_avl_gettagvalue_spec((unsigned char *)TAG_TermCapab,TermCapab,0,3);
	
	switch(temp)		//����CVM���ͽ��в�ͬ�Ĵ���.
	{
	case 0x00:	//��ΪCVMʧ��
		ret = 1;
		break;
	case 0x01://PLAINTEXT PIN VERIFICATION PERFORMED BY ICC
		if((TermCapab[1]&0x80)==0)
		{
			ret = 0;
		}
		else
		{
			ret = 1;
		}
		
		break;
	case 0x02://enciphered PIN verification online
		if((TermCapab[1]&0x40)==0)
		{
			ret = 0;
		}
		else
		{
			ret = 1;
		}
		break;
	case 0x03://Plaintext PIN verification performed by ICC and signature(paper)
		if((TermCapab[1]&0xA0)!=0xA0)
		{
			ret = 0;
		}
		else
		{
			ret = 1;
		}
		break;
	case 0x04://enciphered PIN verification performed by ICC
		if((TermCapab[1]&0x10)==0)
		{
			ret = 0;
		}
		else
		{
			ret = 1;
		}
		break;
	case 0x05://enciphered PIN verification performed by ICC and signature(paper)
		if((TermCapab[1]&0x30)!=0x30)
		{
			ret = 0;
		}
		else
		{
			ret = 1;
		}
		break;
	case 0x1E://signature (paper)
		if((TermCapab[1]&0x20)==0)
		{
			ret = 0;
		}
		else
		{
			ret = 1;
		}
		break;
	case 0x1F://no CVM required
		if((TermCapab[1]&0x08)==0)
		{					
			ret = 0;
		}
		else 
		{
			ret = 1;
		}
		break;
	case 0x20:  //PBOC ֤��
		if((TermCapab[1]&0x01)==0)
		{					
			ret = 0;
		}
		else 
		{
			ret = 1;
		}
		break;
	default:
		ret = 0;
		break;
	}

	return ret;
}




/*******************************************************************
��    ��:
��������: unsigned char AnalyCvmlist(unsigned char *needcvm,unsigned char *nextcvm,unsigned char CVRListLen,AppUnionStruct *tempApp_UnionStruct)
��������: CVM�б����
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:   20130731
********************************************************************/
unsigned short EmvbAnalyCvmlist(unsigned char method,unsigned char condition,unsigned char TransType,unsigned char TermType,unsigned char *CVM_X,unsigned char *CVM_Y)
{

	unsigned char needcvm = 0,nextcvm = 0;
	unsigned short returnvalue;
	unsigned char TermAmtOther[6];
    unsigned char TermAmtOthernotzero = 0;
	unsigned char ret = 0;
	
	#ifdef EMVB_DEBUG
    emvb_printf("\r\n%02x %02x %02x \r\n",TermType,condition,method);
	#endif
    
	
	switch(condition)
	{
		case 0x00://always
			needcvm = 1;
			break;			
		case 0x01://if cash or cashback(EMV2000)��> if unattended cash(modified in EMV4.1,SU16)
			if(TransType==CASH && (TermType & 0x0F) >3 )
			{
				needcvm = 1;
			}
			else nextcvm = 1;
			break;
		case 0x02://if not cash or cashback
		    memset(TermAmtOther,0,sizeof(TermAmtOther));
			dllemvb_avl_gettagvalue_spec((unsigned char *)TAG_AmtOtherNum,TermAmtOther,0,6);
			if(memcmp(TermAmtOther,"\x00\x00\x00\x00\x00\x00",6))
			{
				TermAmtOthernotzero = 1;
			}
			if(TransType!=CASH  && TransType!=CASHBACK&& TermAmtOthernotzero == 0)
			{
				needcvm = 1;					
			}
			else nextcvm = 1;
			break;
		case 0x03://if terminal support CVM   //sxl arm_linux
			 if(Emvb_CheckIfSupportCVM(method))
			 {
			 	needcvm = 1;
			 }
			 else
			 {
			 	nextcvm = 1;
			 }
			break;
		case 0x04://if manual cash (added in EMV4.1,SU16)  //cash�ο�EMV�ĵ�
			if(TransType==CASH && (TermType & 0x0F) <= 3 )
			{
				needcvm = 1;
			}
			else nextcvm = 1;
			break;
		case 0x05://if purchase with cashback (added in EMV4.1,SU16)
		    memset(TermAmtOther,0,sizeof(TermAmtOther));
			dllemvb_avl_gettagvalue_spec((unsigned char *)TAG_AmtOtherNum,TermAmtOther,0,6);
			if(memcmp(TermAmtOther,"\x00\x00\x00\x00\x00\x00",6))
			{
				TermAmtOthernotzero = 1;
			}
			if(TransType==CASHBACK|| TermAmtOthernotzero )
			{
				needcvm = 1;
			}
			else nextcvm = 1;
			break;
		
		case 0x06://if trans is in App currency and under X value
		    ret  = PaypassbAnalyCvmlist_cmpamount(CVM_X,0);
			if(ret == 0)
			{
				nextcvm = 1;
			}
			else
			{
				needcvm = 1;
			}
			
			break;
		case 0x07://if trans is in App currency and over X value
		    ret  = PaypassbAnalyCvmlist_cmpamount(CVM_X,1);
			if(ret == 0)
			{
				nextcvm = 1;
			}
			else
			{
				needcvm = 1;
			}
			
			break;
		case 0x08://if trans is in App currency and under Y value
			ret  = PaypassbAnalyCvmlist_cmpamount(CVM_Y,0);
			if(ret == 0)
			{
				nextcvm = 1;
			}
			else
			{
				needcvm = 1;
			}
			break;
		case 0x09://if trans is in App currency and over Y value
			ret  = PaypassbAnalyCvmlist_cmpamount(CVM_Y,1);
			if(ret == 0)
			{
				nextcvm = 1;
			}
			else
			{
				needcvm = 1;
			}
			break;
		default:
			nextcvm = 1;
			break;
	}

    returnvalue = nextcvm;
    returnvalue = (returnvalue<<8)|needcvm;
	
	return returnvalue;
}


/*******************************************************************
��    ��:
��������: unsigned char Emv_GetPINTryCount(APDU_SEND *apdu_s)
��������: ����ȡ�����Դ�������
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:   20130731
********************************************************************/
unsigned char Emv_GetPINTryCount(APDU_SEND *apdu_s)
{
	memcpy(apdu_s->Command,"\x80\xCA\x9F\x17",4);
	apdu_s->Lc=0;//no Lc
	apdu_s->Le=256;//Le=0(256)
	apdu_s->EnableCancel = 1;

	return EMV_OK;
}


/*******************************************************************
��    ��:
��������: unsigned char Emv_PlaintextCommand(APDU_SEND *apdu_s,unsigned char *tempPIN)
��������: ��֯����PINУ��
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:   20130731
********************************************************************/
unsigned char Emv_PlaintextCommand(APDU_SEND *apdu_s,unsigned char *tempPIN)
{
	memcpy(apdu_s->Command,"\x00\x20\x00\x80",4);
	apdu_s->Lc=8;
	memcpy(apdu_s->DataIn,tempPIN,8);
	apdu_s->Le=0;//no Le
	apdu_s->EnableCancel = 1;
	return EMV_OK;
}



/*******************************************************************
��    ��:
��������: unsigned char Emv_CommandGetChallenge(APDU_SEND *apdu_s)
��������: ����ȡ���������
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:   20130731
********************************************************************/
unsigned char Emv_CommandOfflineEnc(APDU_SEND *apdu_s,unsigned char *EncPIN,unsigned char EncPINLen)
{
	memcpy(apdu_s->Command,"\x00\x20\x00\x88",4);
	apdu_s->Lc=EncPINLen;
	memcpy(apdu_s->DataIn,EncPIN,EncPINLen);
	apdu_s->Le=0;//no Le

	apdu_s->EnableCancel = 1;
	return EMV_OK;
		
}

/*******************************************************************
��    ��:
��������: unsigned char Emv_CommandGetChallenge(APDU_SEND *apdu_s)
��������: ����ȡ���������
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:  20130731
********************************************************************/
unsigned char Emv_CommandGetChallenge(APDU_SEND *apdu_s)
{
	memcpy(apdu_s->Command,"\x00\x84\x00\x00",4);
	
	apdu_s->Lc=0;//no Lc
	apdu_s->Le=256;//Le=0(256)

    apdu_s->EnableCancel = 1;
	return EMV_OK;
		
}


//20130731
unsigned char Emvb_GetPinTryCount(EMVBAppUnionStruct *tempApp_UnionStruct)
{
    unsigned char PINTryCount;
    APDU_SEND apdu_s;
	APDU_RESP apdu_r;
    unsigned short index;
	unsigned short DataLen;

	dllemvb_avl_delete((unsigned char *)TAG_PINTryCount);
	
	Emv_GetPINTryCount(&apdu_s);
	tempApp_UnionStruct->EMVB_qPBOCIccIsoCommand(&apdu_s,&apdu_r);
	if(apdu_r.ReadCardDataOk != EMV_OK)
	{
	   return ERR_APP_TIMEOUT;
	}
    
    if(apdu_r.SWA == 0x90&&apdu_r.SWB == 0x00)
    {
    	if(memcmp(apdu_r.DataOut,"\x9F\x17",2) == 0)
    	{
    	    index = 2;
    		ParseExtLen(apdu_r.DataOut,&index,&DataLen);
			if(index+DataLen == apdu_r.LenOut)
			{
				if(DataLen == 1)
				{
					dllemvb_avl_set((unsigned char *)TAG_PINTryCount,apdu_r.DataOut[index]);
				}
			}
    	}
    }

	if(dllemvb_avl_checkiftagexist((unsigned char *)TAG_PINTryCount))
	{
		PINTryCount = dllemvb_avl_gettagvalue((unsigned char *)TAG_PINTryCount);
		if(PINTryCount == 0)
		{
		    dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x20);
			return ERR_EMV_CVRFail;
		}
	}

	return EMV_OK;
}


//20130731
unsigned char Emvb_CVMPlainTextPin(EMVBAppUnionStruct *tempApp_UnionStruct)
{
	
	//return ERR_EMV_CVRFail;
    #if 1
    APDU_SEND apdu_s;
	APDU_RESP apdu_r;
	//unsigned short index;
	//unsigned short DataLen;
	
	unsigned char offlineplaintext[20];
	unsigned char retCode;
	unsigned char tempPIN[8],PINLen,i;

	while(1)
	{
		retCode = Emvb_GetPinTryCount(tempApp_UnionStruct);
		if(retCode != EMV_OK)
		{
			return retCode;
		}
		
	    memset(offlineplaintext,0,sizeof(offlineplaintext));
		retCode = tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_OFFLINEPLAINTEXTPIN,offlineplaintext);
		if(retCode != EMV_OK)
		{
		    if(retCode == ERR_EMV_CancelTrans)
		    {
		    	return ERR_EMV_CancelTrans;
		    }
			else if(retCode == ERR_EMV_InputCancel)
			{
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x08);
				dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0xDF);
				return ERR_EMV_CVRFail;
			}
		    else //pin pad err
		    {
		    	dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				return ERR_EMV_CVRFail;
		    }
		}
	    
	    
	    //verify pin input
	    PINLen = strlen((char *)offlineplaintext);
		tempPIN[0]=0x20+PINLen;
		for(i=1;i<8;i++) tempPIN[i]=0xFF;
	    
		
		Emv_PIN_asc_to_bcd((unsigned char*)&tempPIN[1],offlineplaintext,strlen((char *)offlineplaintext));
		Emv_PlaintextCommand(&apdu_s,tempPIN); 
		
		
		tempApp_UnionStruct->EMVB_qPBOCIccIsoCommand(&apdu_s,&apdu_r);
		if(apdu_r.ReadCardDataOk != EMV_OK)
		{
		   return ERR_APP_TIMEOUT;
		}
        
		
		if(apdu_r.SWA == 0x90&&apdu_r.SWB == 0x00)
		{
		    offlineplaintext[0] = 0;
		    tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_INPUTPINSTATUS,offlineplaintext);
		    dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0x7F);
			return EMV_OK;
		}
		else if(apdu_r.SWA == 0x69&&(apdu_r.SWB == 0x83||apdu_r.SWB == 0x84))
		{
			dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x20);
			return ERR_EMV_CVRFail;
		}
		else if(apdu_r.SWA == 0x63&&(apdu_r.SWB&0xF0)== 0xC0)
		{
		    offlineplaintext[0] = 1;
			offlineplaintext[1] = apdu_r.SWB - 0xC0;
		    tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_INPUTPINSTATUS,offlineplaintext);
			if(apdu_r.SWB == 0xC0)
			{
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x20);
				return ERR_EMV_CVRFail;
			}
			
		}
        else
        {
        	return ERR_EMV_IccReturn;
        }
		
	}
	
	//return EMV_OK;
	#endif
	
	
}

//20130731
unsigned char Emvb_CVMOnlineEncPin(EMVBAppUnionStruct *tempApp_UnionStruct)
{
    
	//Ĭ����֧�ֵ�
	unsigned char tempCreditPwd[8];
	unsigned char retCode;
	
	tempApp_UnionStruct->EMVTradeParam->cvmonlinepinreq = 1;
	memset(tempCreditPwd,0,sizeof(tempCreditPwd));
	retCode = tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_ONLINEPIN,tempCreditPwd);
	if(retCode == EMV_OK)
	{

        dllemvb_avl_createsettagvalue((unsigned char *)TAG_PIN,tempCreditPwd,8);
        dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x04); //Online PIN entered
        return EMV_OK;
	}
	else if(retCode == ERR_EMV_InputCancel)
    {
        dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x08);
        dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0xDF);
        return ERR_EMV_CVRFail;
    }

    if(retCode == ERR_EMV_CancelTrans)
    {
        return ERR_EMV_CancelTrans;
    }
    else
    {
        dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
        return ERR_EMV_CVRFail;
    }

    #if 0
	unsigned char retCode;
    unsigned char tempCreditPwd[20];
unsigned char PINLen;
   unsigned char  tempPIN[8];
   unsigned char i,k;
  unsigned char   PAN[10];
  unsigned short PANLen;
  unsigned char   buf[20],PanBlockAsc[16],PanBlockBcd[8];
  
  unsigned char TermPINDesKey[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    
	memset(tempCreditPwd,0,sizeof(tempCreditPwd));
	retCode = tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_ONLINEPIN,tempCreditPwd);
	if(retCode == EMV_OK)
    {
    #if 1
        PINLen = strlen((char *)tempCreditPwd);
	tempPIN[0]=PINLen;
	for(i=1;i<8;i++) tempPIN[i]=0xFF;

	Emv_PIN_asc_to_bcd((unsigned char*)&tempPIN[1],tempCreditPwd,PINLen);

    	memset(PAN,0,sizeof(PAN));
	dllemvb_avl_gettagvalue_all((unsigned char *)TAG_PAN,PAN,&PANLen);
    if(PANLen>10) PANLen=10;	
    k = 0;
	for(i=0;i<PANLen;i++)
	{
		if((PAN[i]&0xF0)==0xF0)
			break;
		k++;
		if((PAN[i]&0x0F)==0x0F)
			break;
		k++;
	}
    memset(buf,0,sizeof(buf));
	EMVbcd_to_asc(buf,PAN,k);
	memset(PanBlockAsc,'0',sizeof(PanBlockAsc));
	if(k>0)
	{
		PANLen=k-1;
		if(PANLen>12) PANLen=12;
		for(i=0;i<PANLen;i++)
			PanBlockAsc[15-i]=buf[k-i-2];
	}		
	Emv_PIN_asc_to_bcd(PanBlockBcd,PanBlockAsc,16);
	
	
	for(i=0;i<8;i++)
		tempPIN[i]^=PanBlockBcd[i];


	Emvdes(tempPIN,tempCreditPwd,TermPINDesKey,ENCRYPT);
	

    #endif
			
        dllemvb_avl_createsettagvalue((unsigned char *)TAG_PIN,tempCreditPwd,8);
        dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x04); //Online PIN entered

        return EMV_OK;
    }
	else if(retCode == ERR_EMV_InputCancel)
	{
		dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x08);
		dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0xDF);
		return ERR_EMV_CVRFail;
	}
	if(retCode == ERR_EMV_CancelTrans)
	{
		return ERR_EMV_CancelTrans;
	}
	else
	{
		dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
		return ERR_EMV_CVRFail;
	}
	#endif
	
}

/*******************************************************************
��    ��:
��������: unsigned char Emv_GetICCPIN_EPK(AppUnionStruct *tempApp_UnionStruct)
��������: ��ȡ�ѻ����ļ�������
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:  20130731
********************************************************************/
void Emv_FillICCPIN_EPK(unsigned char* ICCPIN_EPKData,ICCPIN_EPK_RECOVER* recovICCPIN_EPK,unsigned char TempIPKModulLen)
{
	unsigned char i;
	recovICCPIN_EPK->DataHead=ICCPIN_EPKData[0];
	recovICCPIN_EPK->CertFormat=ICCPIN_EPKData[1];
	memcpy(recovICCPIN_EPK->AppPAN,(unsigned char*)&ICCPIN_EPKData[2],10);
	memcpy(recovICCPIN_EPK->ExpireDate,(unsigned char*)&ICCPIN_EPKData[12],2);
	memcpy(recovICCPIN_EPK->CertSerial,(unsigned char*)&ICCPIN_EPKData[14],3);
	recovICCPIN_EPK->HashInd=ICCPIN_EPKData[17];
	recovICCPIN_EPK->ICCPIN_EPKAlgoInd=ICCPIN_EPKData[18];
	recovICCPIN_EPK->ICCPIN_EPKLen=ICCPIN_EPKData[19];
	recovICCPIN_EPK->ICCPIN_EPKExpLen=ICCPIN_EPKData[20];
	memcpy(recovICCPIN_EPK->ICCPIN_EPKLeft,(unsigned char*)&ICCPIN_EPKData[21],TempIPKModulLen-42);
	for(i=0;i<20;i++)
		recovICCPIN_EPK->HashResult[i]=ICCPIN_EPKData[TempIPKModulLen-21+i];
	recovICCPIN_EPK->DataTrail=ICCPIN_EPKData[TempIPKModulLen-1];
}

/*******************************************************************
��    ��:
��������: unsigned char Emv_GetICCPIN_EPK(AppUnionStruct *tempApp_UnionStruct)
��������: ��ȡ�ѻ����ļ�������
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:  20130731
********************************************************************/
unsigned char Emvb_GetICCPIN_EPK(EMVBAppUnionStruct *tempApp_UnionStruct)
{
	
	unsigned char *ICCPIN_EPKData,*ICCPIN_EPKToSign,ICCPIN_EPKHash[20];  //[1024]      [248]
	unsigned char i,byteRecovPAN[20],byteICCPAN[20];
	unsigned short index;
	ICCPIN_EPK_RECOVER *recovICCPIN_EPK;
    
    unsigned char ICCPIN_EPKCertbExist = 0,ICCPIN_EPKExpbExist = 0;
	EMVTAGCVLITEM *ICCPIN_EPKCertitem,*ICCPIN_EPKExpitem;
	EMVTAGCVLITEM *item,*ICCPIN_EPKRemitem = NULL;
    EMVTAGCVLITEM *IPKExpitem = NULL;
	unsigned char IPKExpbExist;
    
    ICCPIN_EPKCertitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKCert,&ICCPIN_EPKCertbExist);
	ICCPIN_EPKExpitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKExp,&ICCPIN_EPKExpbExist);
	IPKExpitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_IPKExp,&IPKExpbExist);
	
    
	if(ICCPIN_EPKCertitem->len!=tempApp_UnionStruct->IPKModulLen)
		return EMV_ERR;


	ICCPIN_EPKData = (unsigned char *)emvblib_malloc(248);
    recovICCPIN_EPK = (ICCPIN_EPK_RECOVER *)emvblib_malloc(sizeof(ICCPIN_EPK_RECOVER));
    
	
	tempApp_UnionStruct->emv_arith_rsarecover(tempApp_UnionStruct->IPKModul,tempApp_UnionStruct->IPKModulLen,IPKExpitem->data,IPKExpitem->len,ICCPIN_EPKCertitem->data,ICCPIN_EPKData);
	
	#ifdef EMVB_DEBUG
		emvb_printf("\nICCPINEPK: ");
		for(i=0;i<tempApp_UnionStruct->IPKModulLen;i++)
			emvb_printf("%02X",ICCPIN_EPKData[i]);
	#endif

	Emv_FillICCPIN_EPK(ICCPIN_EPKData,recovICCPIN_EPK,tempApp_UnionStruct->IPKModulLen);

	if(recovICCPIN_EPK->DataTrail!=0xBC)		//If it is not ��BC��,ICCPK certifate is invalid
	{
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;
	}
	if(recovICCPIN_EPK->DataHead!=0x6A)		//If it is not ��6A��,ICCPK certifate is invalid
	{
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;
	}
	if(recovICCPIN_EPK->CertFormat!=0x04)	//If it is not ��04��, ICCPK certifate is invalid
	{
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;
	}
    
	
    ICCPIN_EPKToSign = (unsigned char *)emvblib_malloc(1024);

	
	index=0;
	memcpy(ICCPIN_EPKToSign,(unsigned char*)&ICCPIN_EPKData[1],tempApp_UnionStruct->IPKModulLen-22);
	index+=tempApp_UnionStruct->IPKModulLen-22;

    
	if(recovICCPIN_EPK->ICCPIN_EPKLen>(tempApp_UnionStruct->IPKModulLen-42))
	{
	    ICCPIN_EPKRemitem = dllemvb_avl_gettagitempointer((unsigned char *)TAG_ICCPIN_EPKRem);
		if(ICCPIN_EPKRemitem != NULL)
		{
			if(ICCPIN_EPKRemitem->len)
			{
				memcpy((unsigned char*)&ICCPIN_EPKToSign[index],(unsigned char*)ICCPIN_EPKRemitem->data,ICCPIN_EPKRemitem->len);
				index+=ICCPIN_EPKRemitem->len;
			}
		}
		
	}
	memcpy((unsigned char*)&ICCPIN_EPKToSign[index],(unsigned char*)ICCPIN_EPKExpitem->data,ICCPIN_EPKExpitem->len);
	index+=ICCPIN_EPKExpitem->len;

	//ICCPIN_EPK sign not use static authentication data for hash verify.
	//memcpy((BYTE*)&ICCPIN_EPKToSign[index],AuthData,AuthDataLen);
	//index+=AuthDataLen;

	//Hash(ICCPIN_EPKToSign,index,ICCPIN_EPKHash);
	tempApp_UnionStruct->emv_arith_hash(ICCPIN_EPKToSign,index,ICCPIN_EPKHash,0);
	
	#ifdef EMVB_DEBUG
		emvb_printf("\ncompuHash: ");
		for(i=0;i<20;i++)
			emvb_printf("%02X",ICCPIN_EPKHash[i]);

		emvb_printf("\nrecovHash: ");
		for(i=0;i<20;i++)
			emvb_printf("%02X",recovICCPIN_EPK->HashResult[i]);

	#endif
	
    
	if(recovICCPIN_EPK->HashInd==0x01)//SHA-1 algorithm
	{
		if(memcmp(recovICCPIN_EPK->HashResult,ICCPIN_EPKHash,20)) 
		{
		    emvblib_free(ICCPIN_EPKToSign);
		    emvblib_free(ICCPIN_EPKData);
		    emvblib_free(recovICCPIN_EPK);
			return EMV_ERR;
		}
	}
	else
	{
	    emvblib_free(ICCPIN_EPKToSign);
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;
	}
    
	//verify if recovered PAN matches PAN in ICC
    item = dllemvb_avl_gettagitempointer((unsigned char *)TAG_PAN);
	if(item == NULL)
	{
	    emvblib_free(ICCPIN_EPKToSign);
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;
	}
	
		
	for(i=0;i<10;i++){
		if(i<item->len)
		{
			byteICCPAN[2*i]=(item->data[i] & 0xF0)>>4;
			byteICCPAN[2*i+1]=item->data[i] & 0x0F;
		}
		byteRecovPAN[2*i]=(recovICCPIN_EPK->AppPAN[i] & 0xF0)>>4;
		byteRecovPAN[2*i+1]=recovICCPIN_EPK->AppPAN[i] & 0x0F;
	}
	for(i=20;i>0;i--)
	{
		if(byteRecovPAN[i-1]!=0x0F)
		{
			if(memcmp(byteRecovPAN,byteICCPAN,i))
			{
			    emvblib_free(ICCPIN_EPKToSign);
			    emvblib_free(ICCPIN_EPKData);
			    emvblib_free(recovICCPIN_EPK);
				return EMV_ERR;
			}
			else
				break;//
		}
	}
	if(i<1)
	{
	    emvblib_free(ICCPIN_EPKToSign);
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;
	}
    
	//verify expiredate is later than current date
	if(Emvb_ExpireDateVerify(recovICCPIN_EPK->ExpireDate)==EMV_ERR)
	{
	    emvblib_free(ICCPIN_EPKToSign);
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;		
	}
    
    
	if(recovICCPIN_EPK->ICCPIN_EPKAlgoInd!=0x01)//other than '01' is not recognised.
	{
	    emvblib_free(ICCPIN_EPKToSign);
	    emvblib_free(ICCPIN_EPKData);
	    emvblib_free(recovICCPIN_EPK);
		return EMV_ERR;
	}
    
	
	#ifdef EMVB_DEBUG
		emvb_printf("\r\n\rICCPIN_EPKModulLen =%02x\n\r",recovICCPIN_EPK->ICCPIN_EPKLen);
	#endif
	if(recovICCPIN_EPK->ICCPIN_EPKLen<=tempApp_UnionStruct->IPKModulLen-42)
	{
		memcpy(ICCPIN_EPKData,recovICCPIN_EPK->ICCPIN_EPKLeft,recovICCPIN_EPK->ICCPIN_EPKLen);
	}
	else
	{
		memcpy(ICCPIN_EPKData,recovICCPIN_EPK->ICCPIN_EPKLeft,tempApp_UnionStruct->IPKModulLen-42);
		if(ICCPIN_EPKRemitem != NULL)
		{
		    memcpy((unsigned char*)&ICCPIN_EPKData[tempApp_UnionStruct->IPKModulLen-42],ICCPIN_EPKRemitem->data,recovICCPIN_EPK->ICCPIN_EPKLen-tempApp_UnionStruct->IPKModulLen+42);
		}
		
	}
	
	
	dllemvb_avl_createsettagvalue((unsigned char *)TAG_ICCPIN_EPKModul,ICCPIN_EPKData,recovICCPIN_EPK->ICCPIN_EPKLen);
    
	
	emvblib_free(ICCPIN_EPKToSign);
	emvblib_free(ICCPIN_EPKData);
	emvblib_free(recovICCPIN_EPK);
	return EMV_OK;	
    
	
}

/*******************************************************************
��    ��:
��������: unsigned char Emv_GetPINEncipherEPK(AppUnionStruct *tempApp_UnionStruct)
��������: ��ȡEPK
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:  20130731
********************************************************************/
unsigned char Emvb_GetPINEncipherEPK(EMVBAppUnionStruct *tempApp_UnionStruct)
{

    CAPK_STRUCT *tempcapk;
    unsigned char ICCPIN_EPKCertbExist = 0,ICCPIN_EPKExpbExist = 0;
	//EMVTAGCVLITEM *ICCPIN_EPKCertitem = NULL,*ICCPIN_EPKExpitem = NULL;
    unsigned char ICCPKCertbExist = 0,ICCPKExpbExist = 0;
	//EMVTAGCVLITEM *ICCPKCertitem = NULL,*ICCPKExpitem = NULL;
    
    
	//ICCPIN_EPKCertitem =   ICCPIN_EPKExpitem = 
	tempcapk = tempApp_UnionStruct->EMVTradeParam->CAPK;
	dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKCert,&ICCPIN_EPKCertbExist);
	dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKExp,&ICCPIN_EPKExpbExist);
    dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPKCert,&ICCPKCertbExist);  //ICCPKCertitem =
	dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPKExp,&ICCPKExpbExist);     //ICCPKExpitem =
    
	
	if(ICCPIN_EPKCertbExist == 1 && ICCPIN_EPKExpbExist == 1)
	{
		
		#ifdef EMVB_DEBUG
		emvb_printf("\nuse ICCPIN_EPK for PIN encipher");
		#endif
		
		if(tempcapk->ModulLen==0)
		{
			if(Emvb_GetCAPK(tempApp_UnionStruct)!=EMV_OK)		//retrieval of the certificate authentication public key
			{
				#ifdef EMVB_DEBUG				
				emvb_printf("\nGet CAPK fail");
				#endif
				return ERR_EMV_CVRFail;
			}
		}
		if(tempApp_UnionStruct->IPKModulLen==0)
		{
			if(Emvb_GetIPK(tempApp_UnionStruct)!=EMV_OK)		//retrieval of the issuer public key modulus
			{
				#ifdef EMVB_DEBUG
				emvb_printf("\nGet IPK fail");
				#endif	
				return ERR_EMV_CVRFail;
			}
		}
		
		#ifdef EMVB_DEBUG
			emvb_printf("\nGet IPK(in CVR) ok");
		#endif
		
		if(Emvb_GetICCPIN_EPK(tempApp_UnionStruct)!=EMV_OK)	//retrieval of the ICC PIN encipher public key
		{
			return ERR_EMV_CVRFail;
		}

			#ifdef EMVB_DEBUG
			emvb_printf("\nGet ICCPIN_EPK ok");
			#endif
		return EMV_OK;
	}
	else if(ICCPKCertbExist && ICCPKExpbExist)
	{//ICC PIN Encipher PK Cert and exponent not exist, use ICC PK Cert and exponent if they are exist.
        
		#ifdef EMVB_DEBUG
		emvb_printf("\nuse ICCPK for PIN encipher");
		#endif
        
		if(tempcapk->ModulLen==0)
		{
			if(Emvb_GetCAPK(tempApp_UnionStruct)!=EMV_OK)		//retrieval of the certificate authentication public key
			{
				#ifdef EMVB_DEBUG
				emvb_printf("\nGet CAPK fail");
				#endif
				return ERR_EMV_CVRFail;
			}
		}
		if(tempApp_UnionStruct->IPKModulLen==0)
		{
			if(Emvb_GetIPK(tempApp_UnionStruct)!=EMV_OK)		//retrieval of the issuer public key modulus
			{
				#ifdef EMVB_DEBUG
				emvb_printf("Get IPK fail");
				#endif	
				return ERR_EMV_CVRFail;
			}
		}

		if(tempApp_UnionStruct->ICCPKModulLen==0)
		{
			#ifdef EMVB_DEBUG
			emvb_printf("\r\n Come to Get ICCPK");
			#endif
			if(Emvb_GetICCPK(tempApp_UnionStruct)!=EMV_OK)			//retrieval of the ICC public key
			{
				#ifdef EMVB_DEBUG
				emvb_printf("\nGet ICCPK fail");
				#endif
				return ERR_EMV_CVRFail;
			}
		}
        
		
		#ifdef EMVB_DEBUG
		emvb_printf("\nGet ICCPIN_EPK ok");		
		#endif		
		return EMV_OK;
		
	}
	else
	{
		return ERR_EMV_CVRFail;
	}
}


//20130731
unsigned char Emvb_CVMPlainTextEncPin(EMVBAppUnionStruct *tempApp_UnionStruct)
{
	
    #if 1
     APDU_SEND apdu_s;
	APDU_RESP apdu_r;
	//unsigned short index;
	//unsigned short DataLen;
	
	unsigned char offlineplaintext[20];
	unsigned char retCode;
	//unsigned char tempPIN[8],PINLen;//,i;
	unsigned char Challenge[8];
	unsigned char RandLen;  //[248]    *RandPad,
	unsigned char *EncPIN,EncPINLen;  //[248]   [248] *PINData,
    unsigned char ICCPIN_EPKExpbExist,ICCPIN_EPKCertbExist,ICCPKExpbExist;
    EMVTAGCVLITEM *ICCPIN_EPKExpitem = NULL,*ICCPKExpitem = NULL,*ICCPIN_EPKModulitem = NULL;
    unsigned char ICCPIN_EPKModulbExist = 0;
    unsigned int externalpinpaddatalen = 0;
	
	
	while(1)
	{
		retCode = Emvb_GetPinTryCount(tempApp_UnionStruct);
		if(retCode != EMV_OK)
		{
			return retCode;
		}

		retCode = Emvb_GetPINEncipherEPK(tempApp_UnionStruct);
		if(retCode != EMV_OK)
		{
		    
			return ERR_EMV_CVRFail;
		}


		Emv_CommandGetChallenge(&apdu_s);
		tempApp_UnionStruct->EMVB_qPBOCIccIsoCommand(&apdu_s,&apdu_r);  
		if(apdu_r.ReadCardDataOk != EMV_OK)
		{
		   return ERR_APP_TIMEOUT;
		}
        
		
        if((!(apdu_r.SWA == 0x90&&apdu_r.SWB == 0x00))||(apdu_r.LenOut != 8))
        {
            dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x80);
        	return ERR_EMV_CVRFail;
        }
		memcpy(Challenge,apdu_r.DataOut,8);
		


		#if 0
	    memset(offlineplaintext,0,sizeof(offlineplaintext));
		retCode = tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_OFFLINEENCPIN,offlineplaintext);
		if(retCode != EMV_OK)
		{
		    if(retCode == ERR_EMV_CancelTrans)
		    {
		    	return ERR_EMV_CancelTrans;
		    }
			else if(retCode == ERR_EMV_InputCancel)
			{
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x08);
				dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0xDF);
				return ERR_EMV_CVRFail;
			}
		    else //pin pad err
		    {
		    	dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				return ERR_EMV_CVRFail;
		    }
		}
	    
	    
	    //verify pin input
	    PINLen = strlen((char *)offlineplaintext);
		tempPIN[0]=0x20+PINLen;
		for(i=1;i<8;i++) tempPIN[i]=0xFF;
	    
		
		Emv_PIN_asc_to_bcd((unsigned char*)&tempPIN[1],offlineplaintext,strlen((char *)offlineplaintext));

        ICCPIN_EPKModulitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKModul,&ICCPIN_EPKModulbExist);
        
		RandPad = (unsigned char *)emvblib_malloc(248);
		if(ICCPIN_EPKModulbExist)
		{
		    if(ICCPIN_EPKModulitem->len > 17)
		    {
		        RandLen = ICCPIN_EPKModulitem->len - 17;
				tempApp_UnionStruct->EMVB_RandomNum(RandPad,RandLen);
		    }
		}
        else
        {
			RandLen = 0;
        }

		PINData = (unsigned char *)emvblib_malloc(248);
		EncPIN = (unsigned char *)emvblib_malloc(248);
		
		PINData[0]=0x7F;
		memcpy((unsigned char*)&PINData[1],tempPIN,8);
		memcpy((unsigned char*)&PINData[9],Challenge,8);
		memcpy((unsigned char*)&PINData[17],RandPad,RandLen);

		emvblib_free(RandPad);
        
        
		ICCPIN_EPKCertbExist = dllemvb_avl_checkiftagexist((unsigned char *)TAG_ICCPIN_EPKCert);
        ICCPIN_EPKExpitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKExp,&ICCPIN_EPKExpbExist);
        
        ICCPKExpitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPKExp,&ICCPKExpbExist);
		
		if(ICCPIN_EPKCertbExist && ICCPIN_EPKExpbExist)
		{
		    if(ICCPIN_EPKModulbExist)
		    {
				tempApp_UnionStruct->emv_arith_rsarecover(ICCPIN_EPKModulitem->data,ICCPIN_EPKModulitem->len,ICCPIN_EPKExpitem->data,ICCPIN_EPKExpitem->len,PINData,EncPIN);		
				EncPINLen=ICCPIN_EPKModulitem->len;
		    }
			else
			{
				EncPINLen = 0;
			}
		}
		else
		{
		    if(ICCPKExpbExist)
		    {
				tempApp_UnionStruct->emv_arith_rsarecover(tempApp_UnionStruct->ICCPKModul,tempApp_UnionStruct->ICCPKModulLen,ICCPKExpitem->data,ICCPKExpitem->len,PINData,EncPIN);
		    }
			EncPINLen=tempApp_UnionStruct->ICCPKModulLen;
		}

		#endif

		EncPIN = (unsigned char *)emvblib_malloc(300);
		externalpinpaddatalen = 0;
		memcpy(&EncPIN[externalpinpaddatalen],Challenge,8);
        externalpinpaddatalen += 8;

        RandLen = 0;
        #if 0
		ICCPIN_EPKModulitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKModul,&ICCPIN_EPKModulbExist);
        if(ICCPIN_EPKModulbExist)
		{
		    if(ICCPIN_EPKModulitem->len > 17)
		    {
		        RandLen = ICCPIN_EPKModulitem->len - 17;
		    }
		}
        else
        {
			RandLen = 0;
        }
        #endif
        
        ICCPIN_EPKModulitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKModul,&ICCPIN_EPKModulbExist);
		ICCPIN_EPKCertbExist = dllemvb_avl_checkiftagexist((unsigned char *)TAG_ICCPIN_EPKCert);
        ICCPIN_EPKExpitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPIN_EPKExp,&ICCPIN_EPKExpbExist);
        
        ICCPKExpitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_ICCPKExp,&ICCPKExpbExist);

		#ifdef EMVB_DEBUG
        if(ICCPIN_EPKModulbExist&&ICCPIN_EPKModulitem != NULL)
        {
        	emvb_printf("\r\nICCPIN_EPKModul len = %d\r\n",ICCPIN_EPKModulitem->len);
			for(retCode = 0;retCode < ICCPIN_EPKModulitem->len;retCode ++)
			{
				emvb_printf("%02x ",ICCPIN_EPKModulitem->data[retCode]);
			}
			emvb_printf("\r\n");
        }
		
        if(ICCPIN_EPKExpbExist&&ICCPIN_EPKExpitem != NULL)
        {
        	emvb_printf("\r\nICCPIN_EPK len = %d\r\n",ICCPIN_EPKExpitem->len);
			for(retCode = 0;retCode < ICCPIN_EPKExpitem->len;retCode ++)
			{
				emvb_printf("%02x ",ICCPIN_EPKExpitem->data[retCode]);
			}
			emvb_printf("\r\n");
			
        }
		
        if(ICCPKExpbExist&&ICCPKExpitem != NULL)
        {
        	emvb_printf("\r\nICCPIN_EPK len = %d\r\n",ICCPKExpitem->len);
			for(retCode = 0;retCode < ICCPKExpitem->len;retCode ++)
			{
				emvb_printf("%02x ",ICCPKExpitem->data[retCode]);
			}
			emvb_printf("\r\n");
        }

		#endif
		
		if(ICCPIN_EPKCertbExist && ICCPIN_EPKExpbExist)
		{
		    if(ICCPIN_EPKModulbExist)
		    {
		        EncPIN[externalpinpaddatalen++] = ICCPIN_EPKModulitem->len;
                memcpy(&EncPIN[externalpinpaddatalen],ICCPIN_EPKModulitem->data,ICCPIN_EPKModulitem->len);
				externalpinpaddatalen += ICCPIN_EPKModulitem->len;

				EncPIN[externalpinpaddatalen++] = ICCPIN_EPKExpitem->len;
				memcpy(&EncPIN[externalpinpaddatalen],ICCPIN_EPKExpitem->data,ICCPIN_EPKExpitem->len);
				externalpinpaddatalen += ICCPIN_EPKExpitem->len;
				RandLen = ICCPIN_EPKModulitem->len - 17;
				EncPIN[externalpinpaddatalen++] = RandLen; 
					
				EncPINLen=ICCPIN_EPKModulitem->len;
		    }
			else
			{
				EncPINLen = 0;
			}
		}
		else
		{
		    if(ICCPKExpbExist)
		    {
		        EncPIN[externalpinpaddatalen++] = tempApp_UnionStruct->ICCPKModulLen;
                memcpy(&EncPIN[externalpinpaddatalen],tempApp_UnionStruct->ICCPKModul,tempApp_UnionStruct->ICCPKModulLen);
				externalpinpaddatalen += tempApp_UnionStruct->ICCPKModulLen;

				EncPIN[externalpinpaddatalen++] = ICCPKExpitem->len;
				memcpy(&EncPIN[externalpinpaddatalen],ICCPKExpitem->data,ICCPKExpitem->len);
				externalpinpaddatalen += ICCPKExpitem->len;
                RandLen = tempApp_UnionStruct->ICCPKModulLen - 17;
				EncPIN[externalpinpaddatalen++] = RandLen; 
				
				EncPINLen=ICCPIN_EPKModulitem->len;
				
		    }
			EncPINLen=tempApp_UnionStruct->ICCPKModulLen;
		}

		if(EncPINLen)
		{
			
		    #ifdef EMVB_DEBUG
			emvb_printf("\r\nEncPINLen = %d\r\n",externalpinpaddatalen);
			for(retCode = 0;retCode < externalpinpaddatalen;retCode ++)
			{
				emvb_printf("%02x ",EncPIN[retCode]);
			}
			emvb_printf("\r\n");
			#endif
			
			retCode = tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_OFFLINEENCPIN,EncPIN);
			if(retCode != EMV_OK)
			{
			    emvblib_free(EncPIN);
			    if(retCode == ERR_EMV_CancelTrans)
			    {
			    	return ERR_EMV_CancelTrans;
			    }
				else if(retCode == ERR_EMV_InputCancel)
				{
					dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x08);
					dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0xDF);
					return ERR_EMV_CVRFail;
				}
			    else //pin pad err
			    {
			    	dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
					return ERR_EMV_CVRFail;
			    }
			}
		}
		else
		{
			dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
			emvblib_free(EncPIN);
			return ERR_EMV_CVRFail;
		}
        
		
		
		Emv_CommandOfflineEnc(&apdu_s,&EncPIN[0],EncPINLen);
        
        //emvblib_free(PINData);
		emvblib_free(EncPIN);
		
		
		tempApp_UnionStruct->EMVB_qPBOCIccIsoCommand(&apdu_s,&apdu_r);
		if(apdu_r.ReadCardDataOk != EMV_OK)
		{
		   return ERR_APP_TIMEOUT;
		}
        
		
		if(apdu_r.SWA == 0x90&&apdu_r.SWB == 0x00)
		{
		    offlineplaintext[0] = 0;
		    tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_INPUTPINSTATUS,offlineplaintext);
		    dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0x7F);
			return EMV_OK;
		}
		else if(apdu_r.SWA == 0x69&&(apdu_r.SWB == 0x83||apdu_r.SWB == 0x84))
		{
			dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x20);
			return ERR_EMV_CVRFail;
		}
		else if(apdu_r.SWA == 0x63&&(apdu_r.SWB&0xF0)== 0xC0)
		{
		    offlineplaintext[0] = 1;
			offlineplaintext[1] = apdu_r.SWB - 0xC0;
		    tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_INPUTPINSTATUS,offlineplaintext);
			if(apdu_r.SWB == 0xC0)
			{
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x20);
				return ERR_EMV_CVRFail;
			}
			
		}
        else
        {
        	return ERR_EMV_IccReturn;
        }
		
	}
	#endif
	
}

//20130731
unsigned char Emvb_CVMCardHolderID(EMVBAppUnionStruct *tempApp_UnionStruct)
{
	unsigned char CardHolderIdTypebExist,CardHolderIdNobExist;
	EMVTAGCVLITEM *CardHolderIdTypeitem = NULL,*CardHolderIdNoitem = NULL;
	unsigned char retCode;
    
	CardHolderIdTypeitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_CardHoldIdType,&CardHolderIdTypebExist);
    CardHolderIdNoitem = dllemvb_avl_gettagitempointerandexiststatus((unsigned char *)TAG_CardHoldIdNo,&CardHolderIdNobExist);
    
	if(CardHolderIdNobExist == 0|| CardHolderIdTypebExist == 0)
	{
		return ERR_EMV_CVRFail;
	}

	if(CardHolderIdTypeitem->data[0]>5 ||CardHolderIdNoitem->len == 0)
	{
		return ERR_EMV_CVRFail;
	}

	retCode = tempApp_UnionStruct->EMVB_InputCreditPwd(EMVB_DATAAUTH_VERIFYIDCARD,NULL);
	if(retCode == EMV_OK)
	{
		return EMV_OK;
	}
	else
	{
		return ERR_EMV_CVRFail;
	}
}

/*******************************************************************
��    ��:
��������: unsigned char Paypass_PerformCVM(AppUnionStruct *tempApp_UnionStruct)
��������: �ֿ�����֤
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:   20130731
********************************************************************/
unsigned char Emvb_PerformCVM(EMVBAppUnionStruct *tempApp_UnionStruct,unsigned char method,unsigned char condition,unsigned char *TermCapab)
{
	unsigned char retCode = 0;
	unsigned char temp;
	unsigned char CVMResult[3];



	#ifdef EMVB_DEBUG
    emvb_printf("\r\nEmvb_PerformCVM %02x %02x\r\n",method,TermCapab[1]);
	#endif
    tempApp_UnionStruct->EMVTradeParam->cvmonlinepinreq = 0;
	temp = method&0x3F;
    
	
	switch(temp)		//����CVM���ͽ��в�ͬ�Ĵ���.
	{
		case 0x00:	   //��ΪCVMʧ��
			CVMResult[2]=CVR_FAIL;
			retCode=ERR_EMV_CVRFailALWAYS;
			break;
		case 0x01:    //PLAINTEXT PIN VERIFICATION PERFORMED BY ICC
			if((TermCapab[1]&0x80)==0)//sxl
			{
			    dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				return ERR_EMV_CVRNoSupport;
			}
			if(PINPAD_VALID == 0)
			{
			    
				CVMResult[2]=CVR_FAIL;
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				retCode = ERR_EMV_CVRNoSupport;
			}
			else
			{
				retCode = Emvb_CVMPlainTextPin(tempApp_UnionStruct);
				if(retCode == EMV_OK)
				{
					CVMResult[2]=CVR_SUCCESS;
				}
				else if(retCode == ERR_EMV_CVRFail)
				{
					CVMResult[2]=CVR_FAIL;
				}
			}
			
            break;
		case 0x02:   //enciphered PIN verification online
			if((TermCapab[1]&0x40)==0)//sxl
			{
			    dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				return ERR_EMV_CVRNoSupport;
			}
			if(PINPAD_VALID == 0)
			{
			    
				CVMResult[2]=CVR_FAIL;
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				retCode = ERR_EMV_CVRNoSupport;
			}
			else  //input online enc pin
			{
				retCode = Emvb_CVMOnlineEncPin(tempApp_UnionStruct);

				if(retCode == EMV_OK)
				{
					CVMResult[2]=CVR_UNKNOWN;
				}
				else if(retCode == ERR_EMV_CVRFail)
				{
					CVMResult[2]=CVR_FAIL;
				}
			}
			//dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x04);
			break;
		case 0x03:  //Plaintext PIN verification performed by ICC and signature(paper)
		    if((TermCapab[1]&0xA0)!=0xA0)//sxl
			{
				
				if((TermCapab[1]&0x80)==0) //20130613 2CJ.090.01
				{
			    	dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				}
				return ERR_EMV_CVRNoSupport;
			}
			if(PINPAD_VALID == 0)
			{
			    
				CVMResult[2]=CVR_FAIL;
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
				retCode = ERR_EMV_CVRNoSupport;
			}
			else
			{
				retCode = Emvb_CVMPlainTextPin(tempApp_UnionStruct);
				if(retCode == EMV_OK)
				{
					CVMResult[2]=CVR_UNKNOWN;
					tempApp_UnionStruct->EMVTradeParam->bPrintReceipt = 1;
				}
				else if(retCode == ERR_EMV_CVRFail)
				{
					CVMResult[2]=CVR_FAIL;
				}
			}
			break;
		case 0x04:  //enciphered PIN verification performed by ICC
			if((TermCapab[1]&0x10)==0)//sxl
			{
			    if((TermCapab[1]&0x80)==0)
			    {
			    	dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
					
			    }
				return ERR_EMV_CVRNoSupport;
			}
			if(PINPAD_VALID == 0)
			{
			    if((TermCapab[1]&0x80)==0)
			    {
					dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
			    }
				
				CVMResult[2]=CVR_FAIL;
				retCode = ERR_EMV_CVRNoSupport;
				
			}
			else
			{
				retCode = Emvb_CVMPlainTextEncPin(tempApp_UnionStruct);
				if(retCode == EMV_OK)
				{
					CVMResult[2]=CVR_SUCCESS;
				}
				else if(retCode == ERR_EMV_CVRFail)
				{
					CVMResult[2]=CVR_FAIL;
				}
				
			}
			break;
		case 0x05: //enciphered PIN verification performed by ICC and signature(paper)
			if((TermCapab[1]&0x30)!=0x30)//sxl
			{
			    if((TermCapab[1]&0x80)==0)
			    {
			    	dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
			    }
				return ERR_EMV_CVRNoSupport;
			}
			if(PINPAD_VALID == 0)
			{
			    if((TermCapab[1]&0x80)==0)
			    {
					dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x10);
			    }
				
				CVMResult[2]=CVR_FAIL;
				retCode = ERR_EMV_CVRNoSupport;
				
			}
			else
			{
				retCode = Emvb_CVMPlainTextEncPin(tempApp_UnionStruct);
				if(retCode == EMV_OK)
				{
					CVMResult[2]=CVR_UNKNOWN;
				}
				else if(retCode == ERR_EMV_CVRFail)
				{
					CVMResult[2]=CVR_FAIL;
				}
				
			}
			break;
		case 0x1E://signature (paper)
			#ifdef EMVB_DEBUG
			emvb_printf("\n\r Come to 1E,Sign paper \n\r");
			#endif 
			if((TermCapab[1]&0x20)==0)  //sxl EMV4.1e
			{
				return ERR_EMV_CVRNoSupport;
			}
			
			tempApp_UnionStruct->EMVTradeParam->bPrintReceipt=1;
			CVMResult[2]=CVR_UNKNOWN;
			retCode=EMV_OK;
			break;
		case 0x1F://no CVM required
			#ifdef EMVB_DEBUG
			emvb_printf("\n\r Come to 1F,No cvm required \n\r");
			emvb_printf("\n\r TermCapab[1] =%02x\n\r",TermCapab[1]);
			#endif 
			
			if((TermCapab[1]&0x08)==0)   //sxl EMV4.1E
			{
			     return ERR_EMV_CVRNoSupport;
				//tempterminfo->CVMResult[2]=CVR_FAIL;
				//retCode= ERR_EMV_CVRNoSupport;
				//break;
			}
			dllemvb_avl_setvalue_and((unsigned char *)TAG_TVR,2,0x7F);
			CVMResult[2]=CVR_SUCCESS;
			retCode=EMV_OK;

			break;	
		case 0x20:  
            if((TermCapab[1]&0x01)==0)   //sxl EMV4.1E
			{
		    	return ERR_EMV_CVRNoSupport;
			}
            retCode = Emvb_CVMCardHolderID(tempApp_UnionStruct);
			if(retCode == EMV_OK)
			{
				CVMResult[2]=CVR_SUCCESS;
			}
			else if(retCode == ERR_EMV_CVRFail)
			{
				CVMResult[2]=CVR_FAIL;
			}
			
			break;
		default:
			dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x40);
			CVMResult[2]=CVR_FAIL;//sxl
			return ERR_EMV_CVRFail;
			break;
		
	}

	
	CVMResult[0]=method;
	CVMResult[1]=condition;

	dllemvb_avl_createsettagvalue((unsigned char *)TAG_CVMResult,CVMResult,3);

	
	return retCode;
}

/*******************************************************************
��    ��:
��������: unsigned char Paypass_CardHolderVerf(AppUnionStruct *tempApp_UnionStruct)
��������: �ֿ�����֤
��ڲ���:
�� �� ֵ:
��ص���:
��    ע:
�޸���Ϣ:   20130731
********************************************************************/
unsigned char Emvb_CardHolderVerf(EMVBAppUnionStruct *tempApp_UnionStruct)
{
	unsigned char retCode;
    CVMSTRCUT CVMdata;
	unsigned char NowCVRListLen = 0;
	unsigned char needcvm,nextcvm;
	unsigned short needcvmnextcvm;
	unsigned char TransType,TermType;
	unsigned char TermCapab[3];

	tempApp_UnionStruct->EMVTradeParam->cvmonlinepinreq = 0;


	#ifdef EMVB_DEBUG
    emvb_printf("\r\nEmvb_CardHolderVerf\r\n");
	#endif

	memset(&CVMdata,0,sizeof(CVMSTRCUT));
	retCode = EmvbInitCardHolderVerify(tempApp_UnionStruct,&CVMdata);
    if(retCode == EMV_OK)
    {
    	return EMV_OK;
    }
    
	
	TransType = tempApp_UnionStruct->EMVTradeParam->TransType;
    TermType = dllemvb_avl_gettagvalue((unsigned char *)TAG_TermType);

    memset(TermCapab,0,sizeof(TermCapab));
	dllemvb_avl_gettagvalue_spec((unsigned char *)TAG_TermCapab,TermCapab,0,3);
	
	
	while(NowCVRListLen < CVMdata.CVRListLen)
	{

		needcvmnextcvm = 0;
		needcvmnextcvm = EmvbAnalyCvmlist(CVMdata.CVRList[NowCVRListLen].method,CVMdata.CVRList[NowCVRListLen].condition,TransType,TermType,CVMdata.CVM_X,CVMdata.CVM_Y);
        
		
        needcvm = needcvmnextcvm&0xff;
        nextcvm = (needcvmnextcvm>>8)&0xff;
		
		if(needcvm == 1)
		{
			retCode=Emvb_PerformCVM(tempApp_UnionStruct,CVMdata.CVRList[NowCVRListLen].method,CVMdata.CVRList[NowCVRListLen].condition,TermCapab);

            #ifdef EMVB_DEBUG
            emvb_printf("\r\n Paypass_PerformCVM retCode = %02x \r\n",retCode);
			#endif
			
			if(retCode==EMV_OK)
			{
			    dllemvb_avl_setvalue_or((unsigned char *)TAG_TSI,0,0x40);
				return retCode;
			}
			
			if(retCode == ERR_EMV_IccReturn||retCode == ERR_EMV_CancelTrans||retCode == ERR_APP_TIMEOUT)
			{
				return retCode;
			}
            #ifdef EMVB_DEBUG
            emvb_printf("\r\ntempterminfo->CVRList[tempterminfo->NowCVRListLen].method =%02x \r\n",CVMdata.CVRList[NowCVRListLen].method);
			#endif
			if(retCode == ERR_EMV_CVRFailALWAYS)
			{
			    dllemvb_avl_setvalue_or((unsigned char *)TAG_TSI,0,0x40);
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x80);
				return EMV_OK;
			}
			
			if((CVMdata.CVRList[NowCVRListLen].method & 0x40)==0x00)
			{
			    dllemvb_avl_setvalue_or((unsigned char *)TAG_TSI,0,0x40);
				dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x80);
				return EMV_OK;
			}
			else nextcvm = 1;
			
		}
		if(nextcvm == 1)
		{
			(NowCVRListLen)++;

		}
	}
	dllemvb_avl_setvalue_or((unsigned char *)TAG_TSI,0,0x40);
	dllemvb_avl_setvalue_or((unsigned char *)TAG_TVR,2,0x80);			//set "Cardholder verification was not successful"
	return EMV_OK;
}

#endif

